/*
 * Copyright © 2009 Perseus Project - Tufts University <http://www.perseus.tufts.edu>
 *
 * This file is part of UniCollatorPerseus.
 *
 * OcroPerseus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * OcroPerseus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with OcroPerseus.  If not, see <http://www.gnu.org/licenses/>.
 */

package eu.himeros.ocr.image;

import eu.himeros.alignment.IntArrayAligner;
import eu.himeros.util.IoManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.util.Iterator;
import java.util.Vector;

/**
 *
 * @author Federico Boschetti <federico.boschetti.73@gmail.com>
 */
public class BoxMixer {
    BufferedReader textBr = null;
    BufferedReader autoboxBr = null;
    BufferedReader tessboxBr = null;
    BufferedWriter mixboxWr = null;
    String fileName = null;
    Runtime runtime = null;
    Process proc = null;
    Vector<String> textV = new Vector<String>(100);
    Vector<String> autoboxV = new Vector<String>(100);
    Vector<String> tessboxV = new Vector<String>(100);
    Vector<Integer> autoboxLineNumV = new Vector<Integer>(100);
    Vector<Integer> tessboxLineNumV = new Vector<Integer>(100);
    Vector<Integer> autoboxUppLeftV = new Vector<Integer>(100);
    Vector<Integer> tessboxUppLeftV = new Vector<Integer>(100);
    Vector<Integer> autoboxEndLinePos = new Vector<Integer>(100);
    Vector<Integer> tessboxEndLinePos = new Vector<Integer>(100);
    int autoboxCurrN = 0;
    int autoboxPrevN = 0;
    int autoboxLineNum = 0;
    int tessboxCurrN = 0;
    int tessboxPrevN = 0;
    int tessboxLineNum = 0;
    IntArrayAligner alg = new IntArrayAligner();
    int startPosAb = 0, endPosAb = 0;
    int startPosTb = 0, endPosTb = 0;
    int[] intAbs = new int[1];
    int[] intTbs = new int[1];
    String recChar=""; //recognized character
    int[] coords;
    int[] nextCoords;

    /**
     *
     * @param args
     */
    public BoxMixer(String[] args) {
        init(args);
        readAll();
        mix();
        end();
    }

    /**
     *
     * @param args
     */
    public void init(String[] args) {
        this.fileName = args[0];
        runtime = Runtime.getRuntime();
        try {
            proc = runtime.exec("tesseract " + fileName + ".tif " + fileName + "_ -l gl0 batch.nochop makebox");
            proc.waitFor();
            proc = runtime.exec("mv " + fileName + ".box " + fileName + "_.box");
            proc.waitFor();
        } catch (Exception ex) {
            pst(ex);
        }
        textBr = IoManager.getReader(fileName + ".txt");
        autoboxBr = IoManager.getReader(fileName + "_.box");
        tessboxBr = IoManager.getReader(fileName + "_.txt");
        mixboxWr = IoManager.getWriter(fileName + ".box");
    }

    /**
     *
     */
    private void readAll() {
        String line = null;
        try {
            while ((line = textBr.readLine()) != null) {
                textV.add(line);
            }
            int pos = 0;
            while ((line = autoboxBr.readLine()) != null) {
                autoboxV.add(line);
                autoboxPrevN = autoboxCurrN;
                autoboxCurrN = Integer.parseInt(line.substring(line.indexOf(' ') + 1, line.indexOf(' ', line.indexOf(' ') + 1)));
                autoboxUppLeftV.add(autoboxCurrN);
                if (autoboxCurrN - autoboxPrevN < -10) {
                    autoboxLineNum++;
                    autoboxEndLinePos.add(pos);
                }
                autoboxLineNumV.add(autoboxLineNum);
                pos++;
            }
            autoboxEndLinePos.add(pos);
            pos = 0;
            while ((line = tessboxBr.readLine()) != null) {
                tessboxV.add(line);
                tessboxPrevN = tessboxCurrN;
                tessboxCurrN = Integer.parseInt(line.substring(line.indexOf(' ') + 1, line.indexOf(' ', line.indexOf(' ') + 1)));
                tessboxUppLeftV.add(tessboxCurrN);
                if (tessboxCurrN - tessboxPrevN < -10) {
                    tessboxLineNum++;
                    tessboxEndLinePos.add(pos);
                }
                tessboxLineNumV.add(tessboxLineNum);
                pos++;
            }
            tessboxEndLinePos.add(pos);
        } catch (Exception ex) {
            pst(ex);
        }
    }

    /**
     *
     */
    private void mix() {
        String line = null;
        String autoboxItm = null;
        String tessboxItm = null;
        Iterator<String> autoboxItr = autoboxV.iterator();
        Iterator<String> tessboxItr = tessboxV.iterator();
        if (autoboxV.size() == tessboxV.size()) {
            // mix!
            for (; autoboxItr.hasNext();) {
                autoboxItm = autoboxItr.next();
                if (tessboxItr.hasNext()) {
                    tessboxItm = tessboxItr.next();
                } else {
                    tessboxItm = "#";
                }
                autoboxItm = autoboxItm.substring(0, autoboxItm.indexOf(' '));
                tessboxItm = tessboxItm.substring(tessboxItm.indexOf(' ') + 1, tessboxItm.length());
                try {
                    mixboxWr.write(autoboxItm + " " + tessboxItm);
                    mixboxWr.newLine();
                } catch (Exception ex) {
                    pst(ex);
                }
            }
        } else {
            // don't mix!
            Iterator<Integer> itab = autoboxEndLinePos.iterator();
            Iterator<Integer> ittb = tessboxEndLinePos.iterator();
            while (itab.hasNext()) {
                endPosAb = itab.next().intValue();
                if(ittb.hasNext()){
                    endPosTb = ittb.next().intValue();
                }
                intAbs = new int[endPosAb - startPosAb];
                intTbs = new int[endPosTb - startPosTb];
                for (int i = 0; i < intAbs.length; i++) {
                    intAbs[i] = autoboxUppLeftV.elementAt(startPosAb + i);
                }
                for (int i = 0; i < intTbs.length; i++) {
                    intTbs[i] = tessboxUppLeftV.elementAt(startPosTb + i);
                }
                write();
                startPosAb = endPosAb;
                startPosTb = endPosTb;
            }
        }
    }

    /**
     *
     */
    private void end() {
        try {
            mixboxWr.close();
        } catch (Exception ex) {
            pst(ex);
        }
    }

    /**
     *
     * @param ex
     */
    private void pst(Exception ex) {
        ex.printStackTrace();
    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        BoxMixer bm = new BoxMixer(args);
    }

    /**
     *
     */
    private void write() {
        // INIZIO BLOCCO DA COMPLETARE
        int alignedBoxes[][] = alg.align(intAbs, intTbs);
        int i = startPosAb;
        int j = startPosTb;
        String itmAb = null;
        String itmTb = null;
        String tessToWrite=null;
        boolean except=false;
        for (int k = 0; k < alignedBoxes[0].length; k++) {
            except=false;
            try {
                if (alignedBoxes[0][k] > Integer.MIN_VALUE) {
                    itmAb = autoboxV.elementAt(i);
                    recChar=parseAutoItem(itmAb);
                    k++;
                    while(k<alignedBoxes[0].length&&alignedBoxes[0][k]==Integer.MIN_VALUE){
                        except=true;
                        itmTb=tessboxV.elementAt(j);
                        coords=parseTessItem(itmTb);
                        j++;
                        itmTb=tessboxV.elementAt(j);
                        nextCoords=parseTessItem(itmTb);
                        coords[0]=Math.min(coords[0],nextCoords[0]);
                        coords[1]=Math.min(coords[1],nextCoords[1]);
                        coords[2]=Math.max(coords[2],nextCoords[2]);
                        coords[3]=Math.max(coords[3],nextCoords[3]);
                        k++;
                    }
                    if(except){
                        tessToWrite=coords[0]+" "+coords[1]+" "+coords[2]+" "+coords[3];
                        System.out.println("join boxes: "+recChar+" "+tessToWrite);
                    }
                    k--;
                    i++;
                }
                if (alignedBoxes[1][k] > Integer.MIN_VALUE) {
                    // BEG -- THIS BLOCK IS WRONG AND FULL OF ERRORS!
                    k++;
                    while(k<alignedBoxes[1].length&&alignedBoxes[1][k]==Integer.MIN_VALUE){
                        
                        itmAb=autoboxV.elementAt(i);
                        recChar+=parseAutoItem(itmAb);
                        System.out.println("recChar="+recChar);
                        i++;
                        k++;
                    }
                    k--;                    
                    // END
                    itmTb = tessboxV.elementAt(j);
                    coords=parseTessItem(itmTb);
                    if(!except){
                        tessToWrite=""+coords[0]+" "+coords[1]+" "+coords[2]+" "+coords[3];
                    }
                    j++;
                }
                mixboxWr.write(recChar+" "+tessToWrite);mixboxWr.newLine();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    // FINE BLOCCO DA COMPLETARE
    }

    /**
     *
     * @param str
     * @return
     */
    private String parseAutoItem(String str){
        return str.substring(0,str.indexOf(' '));
    }

    /**
     *
     * @param str
     * @return
     */
    private int[] parseTessItem(String str){
        int[] locCoords=new int[4]; //local coords
        String[] coordStrs=str.substring(str.indexOf(' ')+1,str.length()).split(" ");
        for(int i=0;i<4;i++){
            locCoords[i]=Integer.parseInt(coordStrs[i]);
        }
        return locCoords;
    }

}
